#include <scheme.h>

#include "config.h"
#include "file_access.h"
#include "file_table.h"
#include "file_misc.h"
#include "audit_list.h"
#include "globals.h"
#include "file_mon.h"

#define SYSFS_MAGIC		0x62656572
#define DEVPTS_SUPER_MAGIC	0x1cd1
#define SOCKFS_MAGIC		0x534F434B
#define PROC_SUPER_MAGIC	0x9fa0
#define TMPFS_MAGIC		0x01021994

static int __check_vfsmount(struct vfsmount * mnt)
{
	if(!mnt) return 0;
	if(!mnt->mnt_sb) return 0;
	if(mnt->mnt_sb->s_magic == SYSFS_MAGIC) return 0;
	if(mnt->mnt_sb->s_magic == DEVPTS_SUPER_MAGIC) return 0;
	if(mnt->mnt_sb->s_magic == SOCKFS_MAGIC) return 0;
	if(mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC) return 0;
	if(mnt->mnt_sb->s_magic == TMPFS_MAGIC) return 0;
	
	return 1;
}

void file_mon_free_security(struct file *file)
{
	char * fullPath = NULL;
	char * pagePtr = NULL;
	int file_len = 0, mon_dir_len = 0;
	FILE_CTX * fileCtx = NULL; 	// -- isTarget
 
	fileCtx = file_ctx_lookup((unsigned long)file);	
	if(fileCtx){
 		file_ctx_remove((unsigned long)file);
	}else{
		goto DONE;
	} 

	/*
 
	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) 
		if(!file->f_path.mnt) goto DONE;
		if(!__check_vfsmount(file->f_path.mnt)) goto DONE;
	#else
		if(!file->f_vfsmnt) goto DONE;
		if(!__check_vfsmount(file->f_vfsmnt)) goto DONE;		
	#endif
	
	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) 
		if(!file->f_path.dentry) goto DONE;
		if(!file->f_path.dentry->d_inode) goto DONE;
		if((!S_ISREG(file->f_path.dentry->d_inode->i_mode)) && (!S_ISDIR(file->f_path.dentry->d_inode->i_mode))) goto DONE;		
	#else
		if(!file->f_dentry) goto DONE;
		if(!file->f_dentry->d_inode) goto DONE;
		if((!S_ISREG(file->f_dentry->d_inode->i_mode)) && (!S_ISDIR(file->f_dentry->d_inode->i_mode))) goto DONE;
	#endif	 
	*/

	pagePtr = (char *)__get_free_page(GFP_KERNEL);
	if(!pagePtr) goto DONE;
	
	spin_lock(&fileCtx->lock);	

	fullPath = NULL;
	
	if(fileCtx->fileName){
		strncpy(pagePtr, fileCtx->fileName, PAGE_SIZE);
		pagePtr[PAGE_SIZE - 1] = 0;
		
		file_len = strlen(pagePtr);
		mon_dir_len = strlen(g_globals.watchFolder);
		if(file_len > mon_dir_len){
			if(0 == strncmp(pagePtr, g_globals.watchFolder, mon_dir_len)){
				fullPath = pagePtr;
			}
		}
	}

	spin_unlock(&fileCtx->lock);	

	if(fullPath){
		if(fileCtx->installState.isWritting) {
			if(atomic_read(&g_globals.bWatchFileEvent)){
				audit_list_push_file_operation(fullPath, __OP_TYPE_FILE_CONTENT, fileCtx->uid);
			}
		}
	}
	// -- if(isUpdateTarget || fileIsTarget){
	// -- 	wlMsgListReportUpdateEvent(FALSE, TRUE, FALSE, FALSE, fullPath, taskId);	
	// -- }else{
	// -- 	wlMsgListReportInstallEvent(FALSE, TRUE, FALSE, FALSE, fullPath);	
	// -- }
DONE:	
	if(pagePtr){
		free_page((unsigned long)pagePtr);
	}	
	if(fileCtx){
		xobject_release(fileCtx);
	} 
	return;		 
}
 
int file_mon_alloc_security(struct file *file)
{
	FILE_CTX * fileCtx = NULL; 	// -- isTarget
 
	fileCtx = file_ctx_insert((long)file);
	if(fileCtx){ 
		fileCtx->uid = __xcurrent_uid();
	}
	
DONE:
 	
	if(fileCtx){
		xobject_release(fileCtx);
	}
 
	return 0;	
}

int file_mon_permission_check(struct file *file, int mask)
{
	int retval = 0;
	char * fullPath = NULL;
	char * pagePtr = NULL;
	FILE_CTX * fileCtx = NULL; 
	int bNoName = 0;
	int bNeedAclCheck = 0;

	if(mask & (MAY_APPEND | MAY_WRITE)){
		// -- fileCtx->installState.isWritting = 1;
	}
	
	fileCtx = file_ctx_lookup((unsigned long)file);
	if(!fileCtx){
		goto DONE;
	}

	if(mask & (MAY_APPEND | MAY_WRITE)){

		spin_lock(&fileCtx->lock);	

		if(!fileCtx->installState.isWritting){
			fileCtx->installState.isWritting = 1;
		}

		spin_unlock(&fileCtx->lock);	
	}

	spin_lock(&fileCtx->lock);	
	
	bNeedAclCheck = (!fileCtx->acl.bChecked);
	if(!fileCtx->fileName){
		bNoName = 1;
	}else{
		bNoName = 0;
	}
	
	spin_unlock(&fileCtx->lock);

	if(bNoName){
		char * __path = NULL;
		
		pagePtr = (char *)__get_free_page(GFP_KERNEL);
		if(!pagePtr) goto DONE;
		
		#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) 
			// -- fullPath = __get_full_path(file->f_path.dentry, file->f_path.mnt);
		#else
			// -- fullPath = __get_full_path(file->f_dentry, file->f_vfsmnt);	
		#endif

		fullPath = get_file_path(file, pagePtr, PAGE_SIZE);
		if(!fullPath) goto DONE;
		
		// -- printk("file's path = %s\n", fullPath);
		
		__path = (char * )kmalloc(strlen(fullPath) + 1, GFP_KERNEL);
		if(__path){
			strcpy(__path, fullPath);

			spin_lock(&fileCtx->lock);	
			
			if(!fileCtx->fileName){
				fileCtx->fileName = __path;
			}else{
				kfree(__path);
				__path = NULL;
			}

			spin_unlock(&fileCtx->lock);	
		}
	}	
	

	if(bNeedAclCheck){
		spin_lock(&fileCtx->lock);
		fileCtx->acl.bChecked = 1;
		spin_unlock(&fileCtx->lock);

		if(mask & MAY_READ){
			if(0 != file_access(file, fileCtx->fileName)){
				retval = -EACCES;
			}
		}
	}
 
DONE:
	if(pagePtr){
		free_page((unsigned long)pagePtr);
	}	
	if(fileCtx){
		xobject_release(fileCtx);
	}	
	// -- if(fullPath){
	// --	kfree(fullPath);
	// -- } 
 
	return retval;
}


